package com.eddie.config;

import com.eddie.annotation.TenantSelector;
import com.eddie.factorybean.TenantSelectorFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Eddie
 */
@Configuration
public class TenantSelectorAutoConfiguration implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        String[] beanDefinitionNames = registry.getBeanDefinitionNames();
        Map<Class<?>, List<Class<?>>> superclassMap = new HashMap<>();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionName);
            Class<?> beanClass = this.forName(beanDefinition.getBeanClassName());
            TenantSelector tenantSelector = beanClass.getAnnotation(TenantSelector.class);
            if (tenantSelector != null) {
                Class<?> superclass = beanClass.getSuperclass();
                superclassMap.compute(superclass, (key, value) -> {
                    if (value == null) {
                        value = new ArrayList<>();
                    }
                    value.add(beanClass);
                    return value;
                });
            }
        }
        superclassMap.forEach((superclass, subclasses) -> registerProxyBean(superclass, subclasses, registry));
    }

    private Class<?> forName(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(className + " class not found!", e);
        }
    }

    private void registerProxyBean(Class<?> superclass, List<Class<?>> subclasses, BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder proxyBeanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TenantSelectorFactoryBean.class);
        proxyBeanDefinitionBuilder.addConstructorArgValue(superclass);
        proxyBeanDefinitionBuilder.addConstructorArgValue(subclasses);

        char[] proxyBeanName = superclass.getSimpleName().toCharArray();
        proxyBeanName[0] = Character.toLowerCase(proxyBeanName[0]);
        registry.registerBeanDefinition(new String(proxyBeanName), proxyBeanDefinitionBuilder.getBeanDefinition());
    }
}
